package main

import (
	"fmt"
	"net" //做网络socket开发，net包必备!
	"time"

	"github.com/garyburd/redigo/redis"
)

//服务器连接使用：func Listen(net, laddr string) (Listener, error)
var Connchan chan net.Conn

func main() {
	Connchan = make(chan net.Conn, 2)
	fmt.Println("服务器开始监听...")
	//1、tcp表示使用网络协议是tcp，其他协议不接收
	//2、0.0.0.0:8888 表示在本地监听8888端口
	listen, err := net.Listen("tcp", "0.0.0.0:8888") //我在本地8888端口监听
	if err != nil {
		fmt.Println("Listen err :", err)
		return
	}
	defer listen.Close() //延时关闭listen

	//循环等待客户端来连接！
	for {
		//等待客户端来连接我
		fmt.Println("等待客户端来连接...")
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("Accept() Error : ", err)
		} else {
			fmt.Printf("Accept() suc :%v   客户端ip = %v\n", conn, conn.RemoteAddr().String())
		}
		//这里准备一个go协程，来为客户服务！
		Connchan <- conn
		go processRequest(conn)
	}
	//创建客户AB管道

}

func processRequest(conn net.Conn) { //接收一个conn ，以明确是连接哪个客服端，以便为哪个客户端服务
	rconn, err := redis.Dial("tcp", "127.0.0.1:6379")
	if err != nil {
		fmt.Println("Redis Connect Error!")
	}
	defer rconn.Close()

	//1、
	defer conn.Close() //结束时要及时关闭连接，否则服务器会因为连接太多没有释放而连不上了
	for {
		v := <-Connchan
		//fmt.Println(v.RemoteAddr().String(),"---",conn.RemoteAddr().String())
		if v.RemoteAddr().String() != conn.RemoteAddr().String() {
			go replyother(conn.RemoteAddr().String(), v, rconn)
			break
		}
		Connchan <- v
	}
	//2、循环接收客户端发送的数据  : Read(b []byte) (n int, err error)  Read从连接中读取数据
	///fmt.Printf("服务器在等待%v的输入...\n",conn.RemoteAddr().String())
	for {
		//先创建一个新的切片
		buf := make([]byte, 1024)
		//从连接读取数据到buf切片上
		//1、等待客户端通过conn发送信息
		//2、如果客户端没有write[发送]，那么协程就会阻塞在这里！！！

		n, err := conn.Read(buf)
		if err != nil { //如果连接异常退出，也会报错
			fmt.Println("与客户端（", conn.RemoteAddr().String(), "）断开连接err:", err)
			return
		}
		//3、显示客户端发送的内容到服务器的终端
		str := fmt.Sprintf(string(buf[:n])) //这个n很重要，显示所读到的内容，而不是整个切片！！！！
		_, err = rconn.Do("rpush", conn.RemoteAddr().String(), str)
		//回复给客户端
		//n,err = conn.Write([]byte("Server收到了!"))
	}
}

func replyother(redisdb string, conn net.Conn, rconn redis.Conn) {
	defer conn.Close()
	defer rconn.Close()
	fmt.Println("db::::", redisdb)
	for {
		time.Sleep(time.Second)
		len, _ := redis.Int(rconn.Do("llen", redisdb))
		if len > 0 {
			str, err := redis.String(rconn.Do("lpop", redisdb))
			fmt.Println(conn.RemoteAddr().String(), ":", str)
			if err != nil {
				fmt.Println("Do lpop Error ", err)
			}
			str = "收到新消息：     " + str
			_, err = conn.Write([]byte(str))
			if err != nil {
				fmt.Println("relpyother over!")
				return
			}
		}
	}
}
